package com.boarsoft.dao.sharding;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.transaction.annotation.Transactional;

import com.boarsoft.dao.sharding.advice.DaoShardingAdviceImpl;
import com.boarsoft.dao.sharding.bean.ShardingParam;

public class HibernateShardingAdviceImpl extends DaoShardingAdviceImpl {

	protected SessionFactory sessionFactory;

	@Override
	protected Object proceed(Method method, ShardingParam sp, ProceedingJoinPoint jp) throws Throwable {
		Session ss = (Session) sp.getSession();
		boolean isNew = (ss == null);
		try {
			if (isNew) {
				ss = sessionFactory.openSession();
				sp.setSession(ss);
			}
			if (method.isAnnotationPresent(Transactional.class)) {
				// 如果方法有配置事务，并且外层未开启事务，则开启事务
				if (sp.getTransaction() == null) {
					Transactional ta = method.getAnnotation(Transactional.class);
					return this.proceed(ss, ta, jp);
				}
			}
			return jp.proceed();
		} finally {
			if (isNew && ss != null) {
				ss.close();
			}
		}
	}

	protected Object proceed(Session ss, Transactional ta, ProceedingJoinPoint jp) throws Throwable {
		Transaction tx = null;
		try {
			tx = ss.beginTransaction();
			Object r = jp.proceed();
			tx.commit();
			return r;
		} catch (Exception e) {
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		}
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
}
